import React, { useRef, useEffect, useState } from 'react';
import { useFrame, useThree } from '@react-three/fiber';
import * as THREE from 'three';

const EnhancedCameraControls = ({
  enablePan = true,
  enableZoom = true,
  enableRotate = true,
  minDistance = 2,
  maxDistance = 50,
  autoRotate = false,
  autoRotateSpeed = 0.5,
  panSpeed = 0.3,
  rotateSpeed = 0.3,
  zoomSpeed = 0.8,
  target = [0, 0, 0],
  smoothness = 0.05
}) => {
  const { camera, gl } = useThree();
  const [isMouseDown, setIsMouseDown] = useState(false);
  const [mouseButton, setMouseButton] = useState(null);
  const [lastMousePosition, setLastMousePosition] = useState({ x: 0, y: 0 });

  // Camera state
  const spherical = useRef(new THREE.Spherical());
  const targetPosition = useRef(new THREE.Vector3(...target));
  const currentTarget = useRef(new THREE.Vector3(...target));
  const panOffset = useRef(new THREE.Vector3());

  // Smooth interpolation values
  const targetSpherical = useRef(new THREE.Spherical());
  const currentSpherical = useRef(new THREE.Spherical());

  // Damping for smoother movement
  const velocity = useRef({ theta: 0, phi: 0, radius: 0 });
  const damping = 0.85;

  // Initialize camera position
  useEffect(() => {
    const initialPosition = camera.position.clone();
    const initialTarget = new THREE.Vector3(...target);
    const offset = initialPosition.clone().sub(initialTarget);

    spherical.current.setFromVector3(offset);
    targetSpherical.current.copy(spherical.current);
    currentSpherical.current.copy(spherical.current);

    // Clamp initial distance
    spherical.current.radius = Math.max(minDistance, Math.min(maxDistance, spherical.current.radius));
    targetSpherical.current.radius = spherical.current.radius;
    currentSpherical.current.radius = spherical.current.radius;
  }, [camera, target, minDistance, maxDistance]);

  // Mouse event handlers
  useEffect(() => {
    const canvas = gl.domElement;

    const handleMouseDown = (event) => {
      setIsMouseDown(true);
      setMouseButton(event.button);
      setLastMousePosition({ x: event.clientX, y: event.clientY });
      canvas.style.cursor = 'grabbing';
    };

    const handleMouseUp = () => {
      setIsMouseDown(false);
      setMouseButton(null);
      canvas.style.cursor = 'grab';
    };

    const handleMouseMove = (event) => {
      const deltaX = event.clientX - lastMousePosition.x;
      const deltaY = event.clientY - lastMousePosition.y;

      if (isMouseDown && enableRotate) {
        if (mouseButton === 0) { // Left mouse button - rotate
          // Much more gentle rotation with better sensitivity
          const rotationSensitivity = 0.003 * rotateSpeed;
          velocity.current.theta += -deltaX * rotationSensitivity;
          velocity.current.phi += deltaY * rotationSensitivity;

          // Apply velocity to target with damping
          targetSpherical.current.theta += velocity.current.theta;
          targetSpherical.current.phi += velocity.current.phi;

          // Clamp phi to prevent flipping (more generous range)
          targetSpherical.current.phi = Math.max(0.05, Math.min(Math.PI - 0.05, targetSpherical.current.phi));

        } else if (mouseButton === 2 && enablePan) { // Right mouse button - pan
          const panSensitivity = 0.005 * panSpeed * (currentSpherical.current.radius / 10);
          const panDelta = new THREE.Vector3();
          const cameraDirection = new THREE.Vector3();
          camera.getWorldDirection(cameraDirection);

          // Calculate pan vectors relative to camera
          const right = new THREE.Vector3().crossVectors(cameraDirection, camera.up).normalize();
          const up = new THREE.Vector3().crossVectors(right, cameraDirection).normalize();

          // Apply pan movement with distance-based scaling
          panDelta.addScaledVector(right, -deltaX * panSensitivity);
          panDelta.addScaledVector(up, deltaY * panSensitivity);

          targetPosition.current.add(panDelta);
        }
      } else if (!isMouseDown && enableRotate) {
        // Very gentle free camera movement when mouse is not pressed
        const freeSensitivity = 0.0008 * rotateSpeed;
        velocity.current.theta += -deltaX * freeSensitivity;
        velocity.current.phi += deltaY * freeSensitivity;

        targetSpherical.current.theta += velocity.current.theta;
        targetSpherical.current.phi += velocity.current.phi;
        targetSpherical.current.phi = Math.max(0.05, Math.min(Math.PI - 0.05, targetSpherical.current.phi));
      }

      setLastMousePosition({ x: event.clientX, y: event.clientY });
    };

    const handleWheel = (event) => {
      if (!enableZoom) return;

      event.preventDefault();
      // Smoother zoom with configurable speed
      const zoomFactor = 1 + (event.deltaY > 0 ? 0.05 : -0.05) * zoomSpeed;
      velocity.current.radius += (targetSpherical.current.radius * (zoomFactor - 1));
      targetSpherical.current.radius *= zoomFactor;
      targetSpherical.current.radius = Math.max(minDistance, Math.min(maxDistance, targetSpherical.current.radius));
    };

    const handleContextMenu = (event) => {
      event.preventDefault(); // Prevent right-click context menu
    };

    // Add event listeners
    canvas.addEventListener('mousedown', handleMouseDown);
    canvas.addEventListener('mouseup', handleMouseUp);
    canvas.addEventListener('mousemove', handleMouseMove);
    canvas.addEventListener('wheel', handleWheel, { passive: false });
    canvas.addEventListener('contextmenu', handleContextMenu);

    // Set initial cursor
    canvas.style.cursor = 'grab';

    return () => {
      canvas.removeEventListener('mousedown', handleMouseDown);
      canvas.removeEventListener('mouseup', handleMouseUp);
      canvas.removeEventListener('mousemove', handleMouseMove);
      canvas.removeEventListener('wheel', handleWheel);
      canvas.removeEventListener('contextmenu', handleContextMenu);
      canvas.style.cursor = 'default';
    };
  }, [gl, isMouseDown, mouseButton, lastMousePosition, enableRotate, enablePan, enableZoom,
      minDistance, maxDistance, panSpeed, rotateSpeed, zoomSpeed]);

  // Animation frame update
  useFrame((state, delta) => {
    // Auto-rotate when enabled
    if (autoRotate && !isMouseDown) {
      targetSpherical.current.theta += autoRotateSpeed * delta;
    }

    // Apply damping to velocity for smoother movement
    velocity.current.theta *= damping;
    velocity.current.phi *= damping;
    velocity.current.radius *= damping;

    // Enhanced smooth interpolation with adaptive smoothness
    const adaptiveSmoothing = smoothness * (1 + Math.abs(velocity.current.theta) + Math.abs(velocity.current.phi));
    const clampedSmoothing = Math.min(adaptiveSmoothing, 0.3);

    currentSpherical.current.theta = THREE.MathUtils.lerp(
      currentSpherical.current.theta,
      targetSpherical.current.theta,
      clampedSmoothing
    );
    currentSpherical.current.phi = THREE.MathUtils.lerp(
      currentSpherical.current.phi,
      targetSpherical.current.phi,
      clampedSmoothing
    );
    currentSpherical.current.radius = THREE.MathUtils.lerp(
      currentSpherical.current.radius,
      targetSpherical.current.radius,
      smoothness * 2 // Faster zoom interpolation
    );

    // Smooth target interpolation
    currentTarget.current.lerp(targetPosition.current, smoothness * 3);

    // Update camera position
    const offset = new THREE.Vector3();
    offset.setFromSpherical(currentSpherical.current);
    camera.position.copy(currentTarget.current).add(offset);
    camera.lookAt(currentTarget.current);

    // Update camera matrix
    camera.updateMatrixWorld();
  });

  return null;
};

export default EnhancedCameraControls;
